package mspbots.hubspot.client.mailchimp.client;

import com.fasterxml.jackson.databind.JsonNode;
import mspbots.hubspot.client.annotation.ApiException;
import org.springframework.http.HttpStatus;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.util.UriBuilder;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.net.URI;
import java.util.function.Function;

/**
 * ConnectWiseService
 *
 * @author Alex bob(https://github.com/vnobo)
 * @date Created by 2019/6/5
 */
public abstract class BaseClient {

    private final WebClient webClient;

    protected BaseClient(WebClient webClient) {
        this.webClient = webClient;
    }

    public <T> Flux<T> fetch(Function<UriBuilder, URI> uriFunction, Class<T> responseType) {
        return this.webClient.get().uri(uriFunction)
                .retrieve()
                .onStatus(HttpStatus::isError, clientResponse -> clientResponse.bodyToMono(JsonNode.class)
                        .map(ApiException::withMsg))
                .bodyToFlux(responseType);

    }

    public Mono<JsonNode> get(Function<UriBuilder, URI> uriFunction) {
        return this.get(uriFunction, JsonNode.class);
    }

    public <T> Mono<T> get(Function<UriBuilder, URI> uriFunction, Class<T> responseType) {
        return this.webClient.get().uri(uriFunction)
                .retrieve()
                .onStatus(HttpStatus::isError, clientResponse -> clientResponse.bodyToMono(JsonNode.class)
                        .map(ApiException::withMsg))
                .bodyToMono(responseType);
    }

    public Mono<JsonNode> put(Function<UriBuilder, URI> uriFunction, Object body) {
        return this.webClient.put().uri(uriFunction)
                .bodyValue(body)
                .retrieve()
                .onStatus(HttpStatus::isError, clientResponse -> clientResponse.bodyToMono(JsonNode.class)
                        .map(ApiException::withMsg))
                .bodyToMono(JsonNode.class);
    }

    public Mono<JsonNode> delete(Function<UriBuilder, URI> uriFunction) {
        return this.webClient.delete().uri(uriFunction)
                .retrieve()
                .onStatus(HttpStatus::isError, clientResponse -> clientResponse.bodyToMono(JsonNode.class)
                        .map(ApiException::withMsg))
                .bodyToMono(JsonNode.class);
    }

    public Mono<JsonNode> post(Function<UriBuilder, URI> uriFunction, Object body) {
        return this.webClient.post().uri(uriFunction)
                .bodyValue(body)
                .retrieve()
                .onStatus(HttpStatus::isError, clientResponse -> clientResponse.bodyToMono(JsonNode.class)
                        .map(ApiException::withMsg))
                .bodyToMono(JsonNode.class);
    }
}
